package application;

import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glVertex2i;

import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import game.CavesList;
import helpers.Text;
import interfaces.IDrawable;
import application.messages.Message;
import application.messages.commands.ConsoleCommand;
import application.messages.commands.parameters.Coordinates2D;
import data.DataManager.BlockType;

/**
 * Implements console, which can be accessed from the game.
 * 
 * @author Drahomir Karchnak, Tomas Zima
 */
public class Console extends RunnableComponent implements IDrawable, Serializable
{
	/**
	 * Called on activation.
	 */
	@Override
	protected void onActivation()
	{
		// 		
	}

	/**
	 * Called on deactivation.
	 */
	@Override
	protected void onDeactivation()
	{
		// 
	}

	/**
	 * THIS METHOD IS EMPTY, DO NOT CALL IT!
	 */
	@Override
	public void enterNewMessage(Message message)
	{
		// 
	}

	/**
	 * Adds new character to the command (call if key was pressed).
	 * 
	 * @param character
	 */
	public void addNewCharacter(char character)
	{
		this.characters += character;
	}
	
	/**
	 * Removes last character of the command (call if backspace was pressed).
	 */
	public void removeLastCharacter()
	{
		String tmp = characters;
		characters = "";
		
		for (int i = 0; i < tmp.length() - 1; i++)
		{
			characters += tmp.charAt(i);
		}
	}
	
	/**
	 * Execute command.
	 * Call if enter was pressed.
	 */
	public void executeCommand()
	{
		// Split command and parameters into array
		String[] parts = characters.split(" ");

		// Make action based on the command
		if (parts[0].equals("setpos"))
		{
			int x;
			int y;
			
			try
			{
				x = Integer.parseInt(parts[1]);
				y = Integer.parseInt(parts[2]);
				
				Message message		= new Message();
				message.command		= ConsoleCommand.SET_PLAYER_POSITION;
				message.position	= new Coordinates2D(x * 32, y * 32);
				
				messages.push(message);
			}
			catch (ArrayIndexOutOfBoundsException errHandler)
			{
				//
			}
			catch (NumberFormatException errHandler)
			{
				//
			}
		}
		else
		if (parts[0].equals("exit"))
		{
			System.exit(0);
		}
		else
		if (parts[0].equals("addinv"))
		{
			try
			{
				String	blockType	= parts[1];
				int		count		= Integer.parseInt(parts[2]);
				
				Message message		= new Message();
				message.command		= ConsoleCommand.INVENTORY_ADD_BLOCKS;
				message.value		= count;

				message.blockType = BlockType.BLOCK_NONE;
				
				if (blockType.equals("stone"))
				{
					message.blockType = BlockType.BLOCK_STONE;
				}
				else
				if (blockType.equals("coal"))
				{
					message.blockType = BlockType.BLOCK_COAL;
				}
				else
				if (blockType.equals("gold"))
				{
					message.blockType = BlockType.BLOCK_GOLD;
				}
				else
				if (blockType.equals("diamond"))
				{
					message.blockType = BlockType.BLOCK_DIAMOND;
				}
				else
				if (blockType.equals("iron"))
				{
					message.blockType = BlockType.BLOCK_IRON;
				}
				
				messages.push(message);
			}
			catch (Exception errHandler)
			{
				//
			}
		}
		else
		if (parts[0].equals("rancave"))
		{
			Coordinates2D ranCaveCoord = CavesList.getInstance().getRandomCaveCoordinates();
			
			int x = ranCaveCoord.x;
			int y = ranCaveCoord.y;
			
			Message message		= new Message();
			message.command		= ConsoleCommand.SET_PLAYER_POSITION;
			message.position	= new Coordinates2D(x * 32, y * 32);
			
			messages.push(message);
		}
		else
		if (parts[0].equals("script"))
		{
			try
			{
				// Get filename with script (without filetype and path)
				String filename = parts[1];
				
				try
				{
					// Open file with whole path for reading
					FileReader inputFileStream	= new FileReader("res/Scripts/" + filename + ".vex");
					
					// Create temporary variables
					StringBuilder fileContents	= new StringBuilder();
					char buffer[]				= new char[4096];
					int read					= 0;

					// Read whole file into fileContents
					do
					{
						fileContents.append(buffer, 0, read);
						read = inputFileStream.read(buffer);
					}
					while (read >= 0);
					
					// Split whole file into array, where each index is one line
					String stringFileContents	= fileContents.toString();
					String lines[]				= stringFileContents.split("\n");
					
					// Go trough the whole array
					for (int i = 0; i < lines.length; i++)
					{
						// Remove white character ("\n") at the end of string
						lines[i] = lines[i].trim();
						
						this.characters = lines[i];
						this.executeCommand();
					}
				}
				catch (IOException errHandler)
				{
					//
				}
			}
			catch (ArrayIndexOutOfBoundsException errHandler)
			{
				//
			}
		}
		else
		if (parts[0].equals("settime"))
		{
			try
			{
				int hour = Integer.parseInt(parts[1]);
				
				Message msg	= new Message();
				msg.command	= ConsoleCommand.SET_TIME;
				msg.value	= hour;
				
				messages.push(msg);
			}
			catch (ArrayIndexOutOfBoundsException errHandler)
			{
				//
			}
		}
		else
		if (parts[0].equals("setdaylength"))
		{
			try
			{
				int length = Integer.parseInt(parts[1]);
				
				Message msg = new Message();
				msg.command = ConsoleCommand.SET_DAY_LENGTH;
				msg.value	= length * 1000;
				
				messages.push(msg);
			}
			catch (ArrayIndexOutOfBoundsException errHandler)
			{
				//
			}
		}
		else
		if (parts[0].equals("removeshots"))
		{
			Message msg	= new Message();
			msg.command	= ConsoleCommand.REMOVE_ALL_GUNSHOTS;
			messages.push(msg);
		}
		else
		if (parts[0].equals("recharge"))
		{
			Message msg	= new Message();
			msg.command	= ConsoleCommand.SET_FULL_HEALTH;
			messages.push(msg);
		}
		else
		if (parts[0].equals("setimunity"))
		{
			try
			{
				int time = Integer.parseInt(parts[1]);
				
				Message msg	= new Message();
				msg.command	= ConsoleCommand.SET_PLAYER_IMUNITY;
				msg.value	= time;
				
				messages.push(msg);
			}
			catch (ArrayIndexOutOfBoundsException errHandler)
			{
				//
			}
		}
		else
		if (parts[0].equals("delimunity"))
		{
			Message msg = new Message();
			msg.command	= ConsoleCommand.REMOVE_PLAYER_IMUNITY;
			
			messages.push(msg);
		}
		else
		if (parts[0].equals("inflives"))
		{
			Message msg = new Message();
			msg.command = ConsoleCommand.SET_PLAYER_IMMORTALITY;
			
			messages.push(msg);
		}
		else
		if (parts[0].equals("delinflives"))
		{
			Message msg = new Message();
			msg.command = ConsoleCommand.REMOVE_PLAYER_IMMORTALITY;
			
			messages.push(msg);
		}
		else
		if (parts[0].equals("colexp"))
		{
			try
			{
				if (parts[1].equals("down"))
				{
					try
					{
						int size = Integer.parseInt(parts[2]);
						
						Message msg = new Message();
						msg.command = ConsoleCommand.EXPLODE_COLUMN_DOWN;
						msg.value	= size;
						
						messages.push(msg);
					}
					catch (Exception errHandler)
					{
						Message msg = new Message();
						msg.command = ConsoleCommand.EXPLODE_COLUMN_DOWN;
						msg.value	= 0;
						
						messages.push(msg);
					}
				}
				else
				if (parts[1].equals("up"))
				{
					try
					{
						int size = Integer.parseInt(parts[2]);
						
						Message msg = new Message();
						msg.command = ConsoleCommand.EXPLODE_COLUMN_UP;
						msg.value	= size;
						
						messages.push(msg);
					}
					catch (Exception errHandler)
					{
						Message msg = new Message();
						msg.command = ConsoleCommand.EXPLODE_COLUMN_UP;
						msg.value	= 0;
						
						messages.push(msg);
					}
				}
				else
				if (parts[1].equals("both"))
				{
					try
					{
						int size = Integer.parseInt(parts[2]);
						
						Message msg = new Message();
						msg.command = ConsoleCommand.EXPLODE_COLUMN;
						msg.value	= size;
						
						messages.push(msg);
					}
					catch (Exception errHandler)
					{
						Message msg = new Message();
						msg.command = ConsoleCommand.EXPLODE_COLUMN;
						msg.value	= 0;
						
						messages.push(msg);
					}
				}
			}
			catch (ArrayIndexOutOfBoundsException errHandler)
			{
				Message msg = new Message();
				msg.command = ConsoleCommand.EXPLODE_COLUMN;
				msg.value	= 0;
				
				messages.push(msg);
			}
		}
		else
		if (parts[0].equals("removeallblocks"))
		{
			Message msg = new Message();
			msg.command = ConsoleCommand.REMOVE_ALL_BLOCKS;
		
			messages.push(msg);
		}
		else
		if (parts[0].equals("killallenemies"))
		{
			Message msg	= new Message();
			msg.command	= ConsoleCommand.KILL_ALL_ENEMIES;
			
			messages.push(msg);
		}
		else
		if (parts[0].equals("enemies"))
		{
			if (parts.length >= 2)
			{
				Configuration.ENABLE_ENEMIES = (parts[1].equals("enable"));
			}
		}
		
		characters = "";
	}
	
	/**
	 * Returns last message which console produced.
	 * 
	 * @return
	 */
	public Message popMessage()
	{
		return messages.pop();
	}
	
	/**
	 * Redraws console. 
	 */
	@Override 
	public void redraw()
	{
		Window.disableTexColorMixing();
		
		if (this.isActive())
		{
			glColor3f(0.0f, 0.0f, 0.0f);
			
			glBegin(GL_QUADS);
				glVertex2i(50, 50);
				glVertex2i(750, 50);
				glVertex2i(750, 100);
				glVertex2i(50, 100);
			glEnd();
			
			Text t = new Text(80, 60, "> " + characters);
			t.redraw();
		}
	}
	
	/**
	 * Checks if console has new command or not.
	 * 
	 * @return
	 */
	public boolean hasNewCommand()
	{
		if (messages.size() != 0)
		{
			return true;
		}
		else
		{
			return false;
		}
		
	}
	
	private String	characters	= "";
	private Stack<Message> messages = new Stack<Message>();
}
